package net.sf.nwn.jme3;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import com.jme3.bounding.BoundingSphere;
import com.jme3.material.Material;
import com.jme3.math.Matrix4f;
import com.jme3.math.Quaternion;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;

public class ParticleCollection extends Geometry {
	private Mesh quads;
	private FloatBuffer vbuf;
	private FloatBuffer tbuf;
	private IntBuffer ibuf;
	private FloatBuffer cbuf;

	public ParticleCollection(int maxParticles, Material app) {
		super("Particle coll");

		quads = new Mesh();
		quads.setMode(Mode.Triangles);
		//quads.setVertexCount(maxParticles * 4);

		this.vbuf = BufferUtils.createVector3Buffer(maxParticles * 4);
		this.tbuf = BufferUtils.createVector2Buffer(maxParticles * 4);
		this.ibuf = BufferUtils.createIntBuffer(maxParticles * 6);
		this.cbuf = BufferUtils.createFloatBuffer(maxParticles * 16);

		for (int i = 0; i < maxParticles; i++) {
			ibuf.put(i * 4 + 0);
			ibuf.put(i * 4 + 1);
			ibuf.put(i * 4 + 2);
			ibuf.put(i * 4 + 0);
			ibuf.put(i * 4 + 2);
			ibuf.put(i * 4 + 3);
		}

		quads.setBuffer(Type.Position, 3, vbuf);
		quads.setBuffer(Type.TexCoord, 2, tbuf);
		quads.setBuffer(Type.Index, 3, ibuf);
		quads.setBuffer(Type.Color, 4, cbuf);

		setMaterial(app);

		setMesh(quads);
		
		quads.setBound(new BoundingSphere(1,new Vector3f()));

	}

	private float xwOff;
	private float ywOff;
	private float zwOff;
	private float xhOff;
	private float yhOff;
	private float zhOff;

	

	private final Matrix4f localToWorld = new Matrix4f();
	private final Matrix4f localToWorldI = new Matrix4f();
	private Matrix4f eye;
	private final Matrix4f rotT = new Matrix4f();
	private Vector3f eyeVector = new Vector3f();

	public void updateTransforms(Matrix4f eyeToWorld) {
		Transform lt = getWorldTransform();
		
		localToWorld.copy(null);
		localToWorld.setRotationQuaternion(lt.getRotation());
		localToWorld.setScale(lt.getScale());
		//localToWorld.setTranslation(lt.getTranslation());
		
		localToWorld.invert(localToWorldI);
		eye = eyeToWorld;
		eyeVector.set(0, 1, 0);
		eyeVector = eye.mult(eyeVector);
		eyeVector.normalizeLocal();
		
	}

	public Matrix4f getLocalMatrix() {
		return localToWorld;
	}

	public Matrix4f getLocalMatrixI() {
		return localToWorldI;
	}

	public Vector3f getEyeVector() {
		return eyeVector;
	}

	public void updateParticle(int particle, float x, float y, float z, float w, float h, float rotation, float r, float g, float b,
			float a, float[] texcoords, boolean alignToWorldFloor) {
	
		Vector3f unit = new Vector3f();
		
		rotT.setRotationQuaternion((new Quaternion(new float[] {0,0,rotation})));

		
		
		
		
		if ( alignToWorldFloor  ) {
			unit.set(0.5f, 0, 0);
			unit = rotT.mult(unit);
			unit = localToWorldI.mult(unit);
		} else {
			unit.set(0.5f, 0, 0);
			unit = rotT.mult(unit);
			unit = eye.mult(unit);
			unit = localToWorldI.mult(unit);
		}
		
		xwOff = unit.x;
		ywOff = unit.y;
		zwOff = unit.z;

		
		if ( alignToWorldFloor  ) {
			unit.set(0, 0,-0.5f);
			unit = rotT.mult(unit);
			unit = localToWorldI.mult(unit);
		} else {
			unit.set(0, 0.5f, 0);
			unit = rotT.mult(unit);
			unit = eye.mult(unit);
			unit = localToWorldI.mult(unit);
		}
		xhOff = unit.x;
		yhOff = unit.y;
		zhOff = unit.z;

		float hxw = xwOff * w;
		float hxh = xhOff * h;
		float hyw = ywOff * w;
		float hyh = yhOff * h;
		float hzw = zwOff * w;
		float hzh = zhOff * h;

		int i = particle * 4;

		tbuf.put(i * 2, texcoords[0]);
		tbuf.put(i * 2 + 1, texcoords[1]);
		cbuf.put(i * 4 + 0, r);
		cbuf.put(i * 4 + 1, g);
		cbuf.put(i * 4 + 2, b);
		cbuf.put(i * 4 + 3, a);
		vbuf.put(i*3+0, x - hxw + hxh);
		vbuf.put(i*3+1,y - hyw + hyh);
		vbuf.put(i*3+2, z - hzw + hzh);

		i++;
		
		tbuf.put(i * 2, texcoords[2]);
		tbuf.put(i * 2 + 1, texcoords[3]);
		cbuf.put(i * 4 + 0, r);
		cbuf.put(i * 4 + 1, g);
		cbuf.put(i * 4 + 2, b);
		cbuf.put(i * 4 + 3, a);
		vbuf.put(i*3+0,x - hxw - hxh);
		vbuf.put(i*3+1, y - hyw - hyh);
		vbuf.put(i*3+2,z - hzw - hzh);

		i++;
		
		tbuf.put(i * 2, texcoords[4]);
		tbuf.put(i * 2 + 1, texcoords[5]);
		cbuf.put(i * 4 + 0, r);
		cbuf.put(i * 4 + 1, g);
		cbuf.put(i * 4 + 2, b);
		cbuf.put(i * 4 + 3, a);
		vbuf.put(i*3+0,x + hxw - hxh);
		vbuf.put(i*3+1,y + hyw - hyh);
		vbuf.put(i*3+2,z + hzw - hzh);

		i++;
		
		tbuf.put(i * 2, texcoords[6]);
		tbuf.put(i * 2 + 1, texcoords[7]);
		cbuf.put(i * 4 + 0, r);
		cbuf.put(i * 4 + 1, g);
		cbuf.put(i * 4 + 2, b);
		cbuf.put(i * 4 + 3, a);
		vbuf.put(i*3+0,x + hxw + hxh);
		vbuf.put(i*3+1,y + hyw + hyh);
		vbuf.put(i*3+2,z + hzw + hzh);
	}
	
	
	public void afterUpdate() {
		/*ibuf.position(0);
		for (int p = 0; p < particleOrder.length; p++) {
			int i = particleOrder[p];
			ibuf.put(i * 4 + 0);
			ibuf.put(i * 4 + 1);
			ibuf.put(i * 4 + 2);
			ibuf.put(i * 4 + 0);
			ibuf.put(i * 4 + 2);
			ibuf.put(i * 4 + 3);
		}
		
		
		quads.getBuffer(Type.Index).setUpdateNeeded();
		*/
		quads.getBuffer(Type.Position).setUpdateNeeded();
		quads.getBuffer(Type.TexCoord).setUpdateNeeded();
		quads.getBuffer(Type.Color).setUpdateNeeded();
		
		
	}
	/*
	 * public javax.media.j3d.BaseNode cloneNode(boolean forceDuplicate) {
	 * ParticleCollection usc = new ParticleCollection();
	 * 
	 * usc.duplicateNode(this, forceDuplicate); return usc; }
	 * 
	 * public void duplicateNode(javax.BaseNode.j3d.Node originalNode, boolean
	 * forceDuplicate) { super.duplicateNode(originalNode, forceDuplicate);
	 * Shape3D oshape = (Shape3D) originalNode; QuadArray oq = (QuadArray)
	 * oshape.getGeometry(); int maxParticles = oq.getVertexCount() / 4;
	 * 
	 * quads = new QuadArray(maxParticles * 4, QuadArray.COORDINATES |
	 * QuadArray.COLOR_4 | QuadArray.TEXTURE_COORDINATE_2 |
	 * QuadArray.BY_REFERENCE | QuadArray.INTERLEAVED);
	 * quads.setCapability(QuadArray.ALLOW_REF_DATA_WRITE);
	 * quads.setCapability(QuadArray.ALLOW_REF_DATA_READ);
	 * 
	 * verts = new float[maxParticles * 4 * 9];
	 * quads.setInterleavedVertices(verts); setGeometry(quads);
	 * 
	 * }
	 */
}
